package com.huilian.iotbox.data.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.huilian.iotbox.data.enums.IPResultEnum;
import com.huilian.iotbox.data.properties.InterfaceProperties;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class Util {
    //消费币种的最小货币单位（分）,金额不足15位前补0，如金额为15.00，则000000000001500
    public static String formatMoney(Object amount) {
        String out = "";
        DecimalFormat df = new DecimalFormat("###########0.00");
        String s = "";
        if (amount instanceof String) {
            s = df.format(new BigDecimal((String) amount));
        }
        if (amount instanceof BigDecimal) {
            s = df.format(amount);
        }
        if (amount instanceof Double) {
            s = df.format(new BigDecimal((Double) amount));
        }
        s = s.replace(".", "");
        for (int i = s.length(); i < 15; i++) {
            out += "0";
        }
        return out + s;
    }

    /**
     * 生成22位订单号
     *
     * @return
     */
    public static String getOutTradeNo() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        StringBuffer sb = new StringBuffer();
        String dateStr = sdf.format(date);
        int ranNum = (int) ((Math.random() * 9 + 1) * 10000);
        return sb.append(dateStr).append(ranNum).toString();
    }

    /**
     * 生成21位订单号
     *
     * @return
     */
    public static String getOutTradeNoNdj() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        StringBuffer sb = new StringBuffer();
        String dateStr = sdf.format(date);
        int ranNum = (int) ((Math.random() * 9 + 1) * 1000);
        return sb.append(dateStr).append(ranNum).toString();
    }

    /**
     * 生成订单商品核销码
     *
     * @return
     */
    public static String genVerifyCode() {
        String year = new SimpleDateFormat("y").format(new Date());
        String y = year.substring(year.length() - 1);
        String day = String.format("%tj", new Date());
        int ranNum = (int) ((Math.random() * 9 + 1) * 100000);
        String verifyCode = y + day + ranNum;
        return verifyCode;
    }

    public synchronized static String getOutTradeNo2() {
        return RandomStringUtils.random(14, false, true);
    }

    /**
     * 高德地图文档 ip查询是有限制的
     * https://lbs.amap.com/api/webservice/guide/api/ipconfig
     */
    public static String getRegionByIp(String ip) {
        try {
            /**IP地址现在用的本地 后期需要修改 需要修改*/
            String param = "ip" + ip + "&key=" + InterfaceProperties.APP_IP_KEY;
            String result = HttpsMain.httpsReq(InterfaceProperties.REQ_IP_URL, param);
            log.info("--------------------请求高德地图IP返回的结果{}", result);
            Map<String, String> map = JSON.parseObject(result, new TypeReference<Map<String, String>>() {
            });
            log.info("请求高德地图返回的状态码{}", map.get("status"));
            if (IPResultEnum.FAIL.getCode().equals(map.get("status"))) {
                return "IP查询出错";
            }
            if (IPResultEnum.SUCCESS.getCode().equals(map.get("status"))) {
                return map.get("province") + map.get("city");
            }
        } catch (Exception e) {
            log.info("-------------------发现错误发生在{},错误信息--------------------", Util.class, e.getMessage());
        }
        return null;
    }

    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (StringUtils.isNotBlank(ip)) {
            ip = ip.split(",")[0];
        }
        return ip;
    }

    /**
     * @param object 传递过来的类型
     *               将String类型转换为Integer类型
     */
    public static Integer stringConvert(Object object) {
        String str = (String) object;
        if (ObjectUtils.isEmpty(str)) {
            return null;
        }
        return Integer.parseInt(str);
    }

    /**
     * 将传递过来的字符串设置为***
     * 包左不包右
     *
     * @param param 传递过来的字符串
     * @param start 开始替换位置
     * @param end   替换结束位置
     */
    public static String stringConvert(String param, Integer start, Integer end) {
        StringBuilder result1 = new StringBuilder(param);
        int rep = end - start;
        StringBuilder replaceStr = new StringBuilder();
        for (int i = 0; i < rep; i++) {
            replaceStr.append("*");
        }
        return result1.replace(start, end, replaceStr.toString()).toString();
    }

    /**
     * 将传递过来的字符串设置为***
     * 包左不包右
     *
     * @param param  传递过来的字符串
     * @param repstr 自定义替换的符号
     * @param start  开始替换位置
     * @param end    替换结束位置
     */
    public static String stringConvert(String param, String repstr, Integer start, Integer end) {
        StringBuilder result1 = new StringBuilder(param);
        int rep = end - start;
        StringBuilder replaceStr = new StringBuilder();
        for (int i = 0; i < rep; i++) {
            replaceStr.append(repstr);
        }
        return result1.replace(start, end, replaceStr.toString()).toString();
    }

    /**
     * @param url  路径
     * @param name 值名字
     * @return 提取URL中的参数值
     */
    public static String getUrlParam(String url, String name) {
        url += "&";
        String pattern = "(\\?|&){1}#{0,1}" + name + "=[a-zA-Z0-9]*(&{1})";
        Pattern r = Pattern.compile(pattern);
        Matcher matcher = r.matcher(url);
        if (matcher.find()) {
            //System.out.println(matcher.group(0));
            return matcher.group(0).split("=")[1].replace("&", "");
        } else {
            return null;
        }
    }

    /**
     * 若异常出现的不是这个controller类的那么就记录完整信息
     */
    public static String getExceptionInfo(Exception e) {
        StringBuffer sOut = new StringBuffer(e.getMessage() + "\r\n");
        StackTraceElement[] trace = e.getStackTrace();
        int i = 0;
        for (StackTraceElement s : trace) {
            if (i > 10) {
                sOut.append("\tat " + s);
                return sOut.toString();
            }
            sOut.append("\tat " + s + "\r\n");
            i++;
        }
        return sOut.toString();
    }

    /**
     * 解析 用户代理(User-Agent)
     *
     * @param userAgent 用户代理User-Agent ,UA
     * @return "设备类型:%s,操作系统:%s,浏览器:%s,浏览器版本:%s,浏览器引擎:%s,用户代理(User-Agent):[%s]"
     * @author GongLiHai
     * @date 2020/8/25 11:12
     */
    public static Map<String, String> getDevice(String userAgent) {
        //解析agent字符串
        UserAgent ua = UserAgent.parseUserAgentString(userAgent);
        //获取浏览器对象
        Browser browser = ua.getBrowser();
        //获取操作系统对象
        OperatingSystem os = ua.getOperatingSystem();

        /**
         * 设备类型:COMPUTER,
         * 操作系统:Windows 10,
         * 浏览器:Chrome 8,
         * 浏览器版本:88.0.4324.182,
         * 浏览器引擎:WEBKIT,
         * 用户代理(User-Agent):[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36]
         */

//        return String.format("设备类型:%s,操作系统:%s,浏览器:%s,浏览器版本:%s,浏览器引擎:%s,用户代理(User-Agent):[%s]",
//                os.getDeviceType(),
//                os.getName(),
//                browser.getName(),
//                browser.getVersion(userAgent),
//                browser.getRenderingEngine(),
//                userAgent
//        );
        Map<String, String> map = new HashMap<>();
        map.put("browser", browser.getName() + "," + browser.getVersion(userAgent) + "," + browser.getRenderingEngine());
        map.put("system", os.getName());

        return map;
    }

    /**
     * 获取请求设备信息
     *
     * @param request 请求
     * @return String 设备信息 pc端还是手机端
     * @author gaodongyang
     * @date 2020/8/11 14:19
     **/
    public static String getDeviceInfo(HttpServletRequest request) {
        ///定义正则
        String pattern = "^Mozilla/\\d\\.\\d\\s+\\(+.+?\\)";
        String pattern2 = "\\(+.+?\\)";
        ///将给定的正则表达式编译到模式中
        Pattern r = Pattern.compile(pattern);
        Pattern r2 = Pattern.compile(pattern2);

        String userAgent = request.getHeader("User-Agent");
        ///创建匹配给定输入与此模式的匹配器
        Matcher m = r.matcher(userAgent);
        String result = null;
        if (m.find()) {
            result = m.group(0);
        }
        if (result == null) {
            return null;
        }
        Matcher m2 = r2.matcher(result);
        if (m2.find()) {
            result = m2.group(0);
        }
        result = result.replace("(", "");
        result = result.replace(")", "");

        if (StringUtils.isBlank(result)) {
            return null;
        }
        result = result.replace(" U;", "");
        result = result.replace(" zh-cn;", "");

        String android = "Android";
        String iPhone = "iPhone";
        String iPad = "iPad";
        if (result.contains(android) || result.contains(iPhone) || result.contains(iPad)) {
            return "移动端";
        } else {
            return "PC端";
        }
    }

    public static boolean uploadFile2(String host, int port, String username, String password, String basePath,
                                      String filePath, String filename, InputStream input) {
        boolean result = false;
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.setConnectTimeout(4000);
            ftp.connect(host, port);// 连接FTP服务器
            // 如果采用默认端口，可以使用ftp.connect(host)的方式直接连接FTP服务器
            ftp.login(username, password);// 登录
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return result;
            }
//            切换到上传目录
            if (!ftp.changeWorkingDirectory(basePath)) {
                //如果目录不存在创建目录
//            String[] dirs = filePath.split("/");
                String tempPath = basePath;
//            for (String dir : dirs) {
//                if (null == dir || "".equals(dir)) continue;
//                tempPath += "/" + dir;
                if (!ftp.changeWorkingDirectory(tempPath)) {
                    if (!ftp.makeDirectory(tempPath)) {
                        return result;
                    } else {
                        ftp.changeWorkingDirectory(tempPath);
                    }
                }
            }
            log.info("开始上传图片");
//            }
            //设置为被动模式(被动模式还是上传不了图片会超时)
            ftp.enterLocalPassiveMode();
            //设置上传文件的类型为二进制类型
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            ftp.setControlEncoding("UTF-8");
            //上传文件
            if (!ftp.storeFile(new String(filename.getBytes("UTF-8"), "iso-8859-1"), input)) {
                log.info("开始上传图片失败: {}", ftp.storeFile(new String(filename.getBytes("UTF-8"), "iso-8859-1"), input));
                return result;
            }
            input.close();
            ftp.logout();
            result = true;
        } catch (IOException e) {
            e.printStackTrace();
            log.info("上传图片: {}", e);
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {

                }
            }
        }
        return result;
    }

    /**
     * ftp登录
     *
     * @param host
     * @param port
     * @param username
     * @param password
     * @param basePath
     * @return
     */
    public static ChannelSftp ftpLogin(String host, int port, String username, String password, String basePath) {
        ChannelSftp sftp = null;
        try {
            JSch jsch = new JSch();
            jsch.getSession(username, host, port);
            Session sshSession = jsch.getSession(username, host, port);
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            log.info("SFTP Session connected.");
            Channel channel = sshSession.openChannel("sftp");
            channel.connect();
            sftp = (ChannelSftp) channel;
            log.info("获取: " + host);
            sftp.cd(basePath);
            return sftp;
        } catch (Exception e) {
            log.error("异常: " + e.getMessage());
            log.error(e.getMessage());
            return null;
        }
    }
//    public static boolean uploadFile(String host, int port, String username, String password, String basePath,
//                                      String filePath, String filename, InputStream input) {
//        ChannelSftp sftp = null;
//        try {
//            JSch jsch = new JSch();
//            jsch.getSession(username, host, port);
//            Session sshSession = jsch.getSession(username, host, port);
//            sshSession.setPassword(password);
//            Properties sshConfig = new Properties();
//            sshConfig.put("StrictHostKeyChecking", "no");
//            sshSession.setConfig(sshConfig);
//            sshSession.connect();
//            log.info("SFTP Session connected.");
//            Channel channel = sshSession.openChannel("sftp");
//            channel.connect();
//            sftp = (ChannelSftp) channel;
//            log.info("获取: {}" + host);
//            sftp.cd(basePath);
//            sftp.put(input,filename);
//            return true;
//        } catch (Exception e) {
//            log.error("异常: {}",e.getMessage());
//            log.error(e.getMessage());
//            return false;
//        }
//    }

    /**
     * 读取服务器图片
     */

    public static String getEventPicture(String host, int port, String username, String password, String basePath, String sfzh) {
        FTPClient ftpClient = new FTPClient();
        InputStream inputStream = null;
        String re = null;
        try {
            ftpClient.connect(host, port);
            ftpClient.login(username, password);
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            //是否成功登录服务器
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
            }
            //跳转到指定目录
            ftpClient.changeWorkingDirectory(basePath);
            //5.遍历下载的目录
            FTPFile[] fs = ftpClient.listFiles();
            for (FTPFile ff : fs) {
                //解决中文乱码问题，两次解码
                byte[] bytes = ff.getName().getBytes("iso-8859-1");
                String fileName = new String(bytes, "utf-8");
                if (sfzh.equals(fileName)) {
                    inputStream = ftpClient.retrieveFileStream(fileName);
                }
            }

            if (inputStream != null) {
//                byte[] data = null;
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                byte[] tmp = new byte[4024];
//                data = new byte[inputStream.available()];
                int len = 0;

                while ((len = inputStream.read(tmp)) != -1) {
                    outStream.write(tmp, 0, len);
                }
                tmp = outStream.toByteArray();
                Base64.Encoder encoder = Base64.getEncoder();
                re = encoder.encodeToString(tmp);
                System.out.println(re);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != inputStream) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return re;
    }


    public static String repPhone(String phone) {
        return stringConvert(phone, 3, 7);
    }

    public static void main(String[] args) {
        System.out.println(formatMoney("123"));
        System.out.println(RandomStringUtils.random(14, false, true));
    }

}
